﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Jackletter.BlendAuth
{
    public static class BlendExtensions
    {
        #region AuthenticationBuilder Extensions

        /// <summary>
        /// 添加Blend认证
        /// </summary>
        /// <param name="builder">AuthenticationBuilder</param>
        /// <param name="authenticationScheme">认证方案名称</param>
        /// <param name="configureOptions">认证方案配置逻辑</param>
        /// <returns></returns>
        public static AuthenticationBuilder AddBlend(this AuthenticationBuilder builder, string authenticationScheme, Action<BlendAuthenticationOptions> configureOptions)
        {
            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<BlendAuthenticationOptions>, PostConfigureBlendAuthenticationOptions>());
            builder.Services.AddOptions<BlendAuthenticationOptions>(authenticationScheme);
            var options = new BlendAuthenticationOptions();
            configureOptions?.Invoke(options);
            builder.Services.AddSingleton<BlendAuthenticationOptions>(options);
            builder.Services.AddSingleton<ITokenManager, TokenManager>();
            builder.Services.AddHttpContextAccessor();
            builder.Services.AddScoped<BlendUser>(_ => _.GetRequiredService<IHttpContextAccessor>()?.HttpContext?.GetBlendUser());

            return builder.AddScheme<BlendAuthenticationOptions, BlendAuthenticationHandler>(authenticationScheme, authenticationScheme, configureOptions);
        }
        #endregion

        #region HttpContext extensions
        /// <summary>
        /// 登录到系统,返回生成的token
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="userId">用户Id</param>
        /// <param name="slidingWindow">滑动窗口大小</param>
        /// <returns></returns>
        public static string SignInBlend(this HttpContext context, long userId) => SignInBlend(context, userId, null);

        /// <summary>
        /// 登录到系统,返回生成的token
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="userId">用户Id</param>
        /// <param name="slidingWindow">滑动窗口大小</param>
        /// <returns></returns>
        public static string SignInBlend(this HttpContext context, long userId, SignOptions options)
        {
            var tokenManger = context.RequestServices.GetRequiredService<ITokenManager>();
            string token = tokenManger.SignIn(userId, options);
            context.Response.Cookies.Append(tokenManger.Options.TokenInCookieName, token, new CookieOptions()
            {
                Expires = DateTimeOffset.Now.AddYears(100),
                HttpOnly = true,
                SameSite = SameSiteMode.Lax
            });
            return token;
        }

        /// <summary>
        /// 登录到系统,返回生成的token
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="userId">用户Id</param>
        /// <param name="slidingWindow">滑动窗口大小</param>
        /// <returns></returns>
        public static string SignInBlendWithoutCookie(this HttpContext context, long userId, SignOptions options)
        {
            var tokenManger = context.RequestServices.GetRequiredService<ITokenManager>();
            string token = tokenManger.SignIn(userId, options);
            return token;
        }

        /// <summary>
        /// 退出当前登录
        /// </summary>
        /// <param name="context">HttpContext</param>
        public static void SignOutBlend(this HttpContext context)
        {
            var tokenManger = context.RequestServices.GetRequiredService<ITokenManager>();
            tokenManger.SignOut(context.GetBlendUser().Token);
            context.Response.Cookies.Delete(tokenManger.Options.TokenInCookieName);
        }

        /// <summary>
        /// 将指定的用户退出登录
        /// </summary>
        /// <param name="context">HttpContext</param>
        /// <param name="userId">用户Id</param>
        public static void SignOutBlend(this HttpContext context, int userId)
        {
            var tokenManger = context.RequestServices.GetRequiredService<ITokenManager>();
            tokenManger.SignOut(userId);
        }

        /// <summary>
        /// 获取当前登录的用户信息
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static BlendUser GetBlendUser(this HttpContext context)
        {
            var tokenManger = context.RequestServices.GetRequiredService<ITokenManager>();
            string token = context.User?.FindFirst("_token")?.Value;
            return tokenManger.GetUser(token);
        }
        #endregion
    }
}
